package com.skt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skt.domain.DTO.request.CreateRentalOrderRequest;
import com.skt.domain.ENUM.CostumeStatus;
import com.skt.domain.ENUM.RentalOrderStatus;
import com.skt.domain.PO.Costume;
import com.skt.domain.PO.RentalOrder;
import com.skt.domain.PO.RentalOrderItem;
import com.skt.domain.VO.RentalOrderVO;
import com.skt.mapper.CostumeMapper;
import com.skt.mapper.RentalOrderItemMapper;
import com.skt.mapper.RentalOrderMapper;
import com.skt.mapper.UserMapper;
import com.skt.security.LoginUser;
import com.skt.service.RentalOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class RentalOrderServiceImpl extends ServiceImpl<RentalOrderMapper, RentalOrder> implements RentalOrderService {

    private final UserMapper userMapper;
    private final CostumeMapper costumeMapper;
    private final RentalOrderMapper rentalOrderMapper;
    private final RentalOrderItemMapper rentalOrderItemMapper;

    /**
     * 创建订单
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RentalOrderVO createRentalOrder(CreateRentalOrderRequest request) {
        // 1. 获取当前登录用户 ID
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("用户未登录");
        }

        Long userId = null;
        if (authentication.getPrincipal() instanceof LoginUser loginUser) {
            userId = loginUser.getUserId();
        }

        if (userId == null) {
            throw new RuntimeException("无效用户凭证");
        }

        // 2. 参数校验（日期）
        LocalDate startDate = request.getStartDate();
        LocalDate endDate = request.getEndDate();
        List<CreateRentalOrderRequest.CostumeItem> costumeItems = request.getCostumes();

        // startDate,endDate不能为空    startDate不能是过去日期    costumes 列表不能为空
        if (startDate.isAfter(endDate)) {
            throw new RuntimeException("开始日期不能晚于结束日期");
        }

        // 3. 验证用户存在
        if (userMapper.selectById(userId) == null) {
            throw new RuntimeException("用户不存在");
        }

        // 4. 批量获取所有服装 ID
        // 从 costumeItems 列表中提取所有服装ID，并去重后存入一个 Set 集合中。
        Set<Long> costumeIds = costumeItems.stream()
                .map(CreateRentalOrderRequest.CostumeItem::getCostumeId) // 提取ID
                .collect(Collectors.toSet()); // 收集到set去重

        List<Costume> costumes = costumeMapper.selectBatchIds(costumeIds);
        if (costumes.size() != costumeIds.size()) {
            throw new RuntimeException("部分服装ID不存在");
        }

        // 构建 Map 便于查找
        Map<Long, Costume> costumeMap = costumes.stream()
                // 第一个参数 Costume::getId 指定使用服装的 ID 作为 Map 的键。
                // 第二个参数 c -> c 表示将服装对象本身作为 Map 的值。
                .collect(Collectors.toMap(Costume::getId, c -> c));

        // 5. 校验每件服装状态 & 计算总金额
        int totalDays = (int) ChronoUnit.DAYS.between(startDate, endDate) + 1;
        // BigDecimal.ZERO 表示数值 0
        BigDecimal totalAmount = BigDecimal.ZERO;

        for (CreateRentalOrderRequest.CostumeItem item : costumeItems) {
            Long cid = item.getCostumeId();
            Integer quantity = item.getQuantity();

            if (quantity == null || quantity <= 0) {
                throw new RuntimeException("服装数量必须大于0");
            }

            Costume costume = costumeMap.get(cid);
            if (costume == null) {
                throw new RuntimeException("服装ID " + cid + " 不存在");
            }
            if (!CostumeStatus.AVAILABLE.getCode().equals(costume.getStatus())) {
                throw new RuntimeException("服装《" + costume.getName() + "》当前不可租赁");
            }

            // 计算该服装的子金额：日租金 × 数量 × 天数
            BigDecimal subTotal = costume.getRentalPrice()
                    .multiply(BigDecimal.valueOf(quantity))
                    .multiply(BigDecimal.valueOf(totalDays))
                    // 将结果保留 2 位小数，并采用四舍五入
                    .setScale(2, RoundingMode.HALF_UP);

            totalAmount = totalAmount.add(subTotal);
        }

        // 6. 生成订单号
        String orderNo = "R" + // 以字母 "R" 开头，表示 Rental（租赁）订单，便于识别订单类型。
                // 获取当前时间，并格式化为 14位纯数字时间戳，例如：20251014112345
                //（对应 2025年10月14日 11点23分45秒）。
                // 保证订单号按时间有序，也便于人工识别下单时间。
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
                // 生成一个 0 到 999999 之间的随机整数；
                // %06d 表示将其格式化为 6位数字，不足前面补0（如 42 → 000042）；
                // 用于避免同一秒内生成重复订单号（高并发场景下时间戳可能相同）。
                String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));

        // 7. 保存主订单
        RentalOrder order = new RentalOrder()
                .setOrderNo(orderNo)
                .setUserId(userId)
                .setStartDate(startDate)
                .setEndDate(endDate)
                .setTotalDays(totalDays)
                .setTotalAmount(totalAmount)
                .setStatus(RentalOrderStatus.PENDING_PAYMENT.getCode())
                .setRemark(request.getRemark()) // ✅ 设置 remark
                .setCreatedAt(LocalDateTime.now()); // 可选：设置创建时间

        if (this.baseMapper.insert(order) != 1) {
            throw new RuntimeException("创建订单失败");
        }

        // 8. 保存订单明细（使用标准 insert 循环）
        List<RentalOrderItem> orderItems = new ArrayList<>();
        for (CreateRentalOrderRequest.CostumeItem item : costumeItems) {
            Costume costume = costumeMap.get(item.getCostumeId());
            RentalOrderItem orderItem = new RentalOrderItem()
                    .setOrderId(order.getId())
                    .setCostumeId(item.getCostumeId())
                    .setQuantity(item.getQuantity())
                    .setDailyPrice(costume.getRentalPrice())
                    .setCreatedAt(LocalDateTime.now());
            orderItems.add(orderItem);
        }

        if (!orderItems.isEmpty()) {
            for (RentalOrderItem item : orderItems) {
                rentalOrderItemMapper.insert(item);
            }
        }

        // 9. 返回 VO
        RentalOrderVO vo = new RentalOrderVO();
        vo.setId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setStartDate(order.getStartDate());
        vo.setEndDate(order.getEndDate());
        vo.setTotalDays(order.getTotalDays());
        vo.setTotalAmount(order.getTotalAmount());
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(RentalOrderStatus.fromCode(order.getStatus()).getDescription());
        vo.setCreatedAt(order.getCreatedAt());

        return vo;
    }

    /**
     * 查看订单详情
     * @param orderId
     * @param currentUserId
     * @return
     */
    @Override
    public RentalOrderVO getOrderDetail(Long orderId, Long currentUserId) {
        if (orderId == null) {
            throw new RuntimeException("订单ID不能为空");
        }

        // 1. 查询主订单
        RentalOrder order = this.baseMapper.selectById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 2. 权限校验：只能查自己的订单
        if (!order.getUserId().equals(currentUserId)) {
            throw new RuntimeException("无权查看该订单");
        }

        // 3. 查询订单明细
        List<RentalOrderItem> items = rentalOrderItemMapper.selectList(
                new LambdaQueryWrapper<RentalOrderItem>().eq(RentalOrderItem::getOrderId, orderId)
        );

        if (items.isEmpty()) {
            throw new RuntimeException("订单明细不存在");
        }

        // 4. 获取所有 costumeId 并查询服装信息
        List<Long> costumeIds = items.stream()
                .map(RentalOrderItem::getCostumeId)
                .distinct()
                .collect(Collectors.toList());

        List<Costume> costumes = costumeMapper.selectBatchIds(costumeIds);
        Map<Long, Costume> costumeMap = costumes.stream()
                .collect(Collectors.toMap(Costume::getId, c -> c));

        // 5. 构建明细 VO 列表
        List<RentalOrderVO.OrderItemVO> itemVOs = new ArrayList<>();
        for (RentalOrderItem item : items) {
            Costume costume = costumeMap.get(item.getCostumeId());
            if (costume == null) {
                continue; // 跳过已删除的服装（或根据业务决定是否报错）
            }

            BigDecimal subtotal = item.getDailyPrice()
                    .multiply(BigDecimal.valueOf(item.getQuantity()))
                    .multiply(BigDecimal.valueOf(order.getTotalDays()))
                    .setScale(2, RoundingMode.HALF_UP);

            RentalOrderVO.OrderItemVO vo = new RentalOrderVO.OrderItemVO();
            vo.setCostumeId(costume.getId());
            vo.setCostumeName(costume.getName());
            vo.setQuantity(item.getQuantity());
            vo.setDailyPrice(item.getDailyPrice());
            vo.setSubtotal(subtotal);
            itemVOs.add(vo);
        }

        // 6. 构建主 VO
        RentalOrderVO vo = new RentalOrderVO();
        vo.setId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setStartDate(order.getStartDate());
        vo.setEndDate(order.getEndDate());
        vo.setTotalDays(order.getTotalDays());
        vo.setTotalAmount(order.getTotalAmount());
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(RentalOrderStatus.fromCode(order.getStatus()).getDescription());
        vo.setCreatedAt(order.getCreatedAt());
        vo.setItems(itemVOs);

        return vo;
    }

    /**
     * 查询我的订单列表
     * @param pageNum 页码（从1开始）
     * @param pageSize 每页数量
     * @return 订单列表（含明细）
     */
    @Override
    public List<RentalOrderVO> listMyOrders(int pageNum, int pageSize) {
        // 1.身份校验
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("用户未登录");
        }

        Long userId = null;
        Object principal = authentication.getPrincipal();
        if (principal instanceof LoginUser loginUser) {
            userId = loginUser.getUserId();
        } else {
            throw new RuntimeException("不存在该用户");
        }

        if (userId == null) {
            throw new RuntimeException("不存在该用户");
        }

        // 2.分页参数处理
        // Math.max(a, b) 返回 a 和 b 中的较大值，Math.min(a, b) 返回 a 和 b 中的较小值。
        pageNum = Math.max(1, pageNum);
        pageSize = Math.min(50, Math.max(1, pageSize)); // 限制最大50条/页

        // 3.查询订单数据（分页）
        // 创建一个分页对象，指定要查询第 pageNum 页，每页 pageSize 条记录。
        Page<RentalOrder> page = new Page<>(pageNum, pageSize);
        // 调用 MyBatis-Plus 的 selectPage 方法进行分页查询：
        // 条件：user_id = userId（只查当前用户的订单）
        // 排序：按 created_at 字段降序（最新订单在前）
        Page<RentalOrder> orderPage = this.baseMapper.selectPage(
                page,
                new LambdaQueryWrapper<RentalOrder>()
                        .eq(RentalOrder::getUserId, userId)
                        .orderByDesc(RentalOrder::getCreatedAt)
        );

        // 从分页结果中提取当前页的实际订单数据列表。
        List<RentalOrder> orders = orderPage.getRecords();
        // 如果当前页没有订单，直接返回一个不可变的空列表，避免后续处理空指针或无效数据。
        if (orders.isEmpty()) {
            return Collections.emptyList();
        }

        // 4.数据转换（主订单 → VO 基础字段）
        List<RentalOrderVO> voList = orders.stream().map(order -> {
            RentalOrderVO vo = new RentalOrderVO();
            vo.setId(order.getId());
            vo.setOrderNo(order.getOrderNo());
            vo.setStartDate(order.getStartDate());
            vo.setEndDate(order.getEndDate());
            vo.setTotalDays(order.getTotalDays());
            vo.setTotalAmount(order.getTotalAmount());
            vo.setStatus(order.getStatus());
            vo.setStatusDesc(RentalOrderStatus.fromCode(order.getStatus()).getDescription());
            vo.setCreatedAt(order.getCreatedAt());
            return vo;
        }).collect(Collectors.toList());

        // 5.关联信息补充（加载每个订单的明细项及服装信息）
        // 5.1 提取所有订单ID
        List<Long> orderIds = orders.stream()
                .map(RentalOrder::getId)
                .collect(Collectors.toList());

        // 5.2 批量查询所有订单明细
        List<RentalOrderItem> allItems = rentalOrderItemMapper.selectList(
                new LambdaQueryWrapper<RentalOrderItem>()
                        .in(RentalOrderItem::getOrderId, orderIds)
        );

        if (!allItems.isEmpty()) {
            // 5.3 提取所有 costumeId 并批量查询服装
            List<Long> costumeIds = allItems.stream()
                    .map(RentalOrderItem::getCostumeId)
                    .distinct()
                    .collect(Collectors.toList());

            List<Costume> costumes = costumeMapper.selectBatchIds(costumeIds);
            Map<Long, Costume> costumeMap = costumes.stream()
                    .collect(Collectors.toMap(Costume::getId, c -> c));

            // 5.4 按 orderId 分组明细项
            Map<Long, List<RentalOrderItem>> itemsGroupByOrderId = allItems.stream()
                    .collect(Collectors.groupingBy(RentalOrderItem::getOrderId));

            // 5.5 为每个 VO 补充 items
            for (RentalOrderVO vo : voList) {
                List<RentalOrderItem> items = itemsGroupByOrderId.get(vo.getId());
                if (items != null && !items.isEmpty()) {
                    List<RentalOrderVO.OrderItemVO> itemVOs = items.stream().map(item -> {
                        Costume costume = costumeMap.get(item.getCostumeId());
                        if (costume == null) {
                            // 跳过已删除的服装（或设为默认值）
                            return null;
                        }

                        // 计算子金额：日租金 × 数量 × 总天数（来自主订单）
                        BigDecimal subtotal = item.getDailyPrice()
                                .multiply(BigDecimal.valueOf(item.getQuantity()))
                                .multiply(BigDecimal.valueOf(vo.getTotalDays()))
                                .setScale(2, RoundingMode.HALF_UP);

                        RentalOrderVO.OrderItemVO itemVO = new RentalOrderVO.OrderItemVO();
                        itemVO.setCostumeId(costume.getId());
                        itemVO.setCostumeName(costume.getName());
                        itemVO.setQuantity(item.getQuantity());
                        itemVO.setDailyPrice(item.getDailyPrice());
                        itemVO.setSubtotal(subtotal);
                        return itemVO;
                    }).filter(Objects::nonNull).collect(Collectors.toList());

                    vo.setItems(itemVOs);
                } else {
                    vo.setItems(Collections.emptyList());
                }
            }
        } else {
            // 没有明细，统一设为空列表
            voList.forEach(vo -> vo.setItems(Collections.emptyList()));
        }

        // 6.结果封装（已封装在 voList 中）

        // 7.返回结果
        return voList;
    }

    /**
     * 取消未生效的订单
     * @param id 订单ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RentalOrderVO cancelPendingOrder(Long id) {
        // 1. 获取当前用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()
                || "anonymousUser".equals(authentication.getPrincipal())) {
            throw new RuntimeException("用户未登录");
        }

        Long userId;
        Object principal = authentication.getPrincipal();
        if (principal instanceof LoginUser loginUser) {
            userId = loginUser.getUserId();
        } else {
            throw new RuntimeException("用户信息无效");
        }

        if (userId == null) {
            throw new RuntimeException("用户ID不能为空");
        }

        // 2. 校验订单ID
        if (id == null || id <= 0) {
            throw new RuntimeException("订单ID无效");
        }

        // 3. 查询订单
        RentalOrder order = rentalOrderMapper.selectById(id);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 4. 权限校验
        if (order.getUserId() == null || !userId.equals(order.getUserId())) {
            throw new RuntimeException("无权操作该订单");
        }

        // 5. 状态校验：仅允许“待支付”（状态码 1）取消
        if (order.getStatus() != RentalOrderStatus.PENDING_PAYMENT.getCode()) {
            throw new RuntimeException("该订单不可取消");
        }

        // 6. 更新订单状态为“已取消”（状态码 5）
        order.setStatus(RentalOrderStatus.CANCELLED.getCode());
        order.setUpdatedAt(LocalDateTime.now());
        rentalOrderMapper.updateById(order);

        // 7. 【可选】释放关联服装资源
        // TODO: 若需释放服装状态，请实现 CostumeMapper.batchUpdateStatusToAvailable 方法
        //       或在此处手动更新 costume 表的状态字段

        // 8. 构建返回 VO
        RentalOrderVO vo = new RentalOrderVO();
        vo.setId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setStartDate(order.getStartDate());
        vo.setEndDate(order.getEndDate());
        vo.setRemark(order.getRemark());
        vo.setTotalDays(order.getTotalDays());
        vo.setTotalAmount(order.getTotalAmount());
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(RentalOrderStatus.CANCELLED.getDescription());
        vo.setCreatedAt(order.getCreatedAt());

        return vo;
    }
}